<html>
    <head>
        <script>
            (function() {
                // 查找元素的位置
                function findAllOccurrences(arr, target) {
                    var a = []
                    for(var i = 0; i < arr.length; i++) {
                        if(arr[i] == target) {
                            a.push(i)
                        }
                    }
                    return a
                }
                //filter
                function findAllOccurrences_filter(arr, target) {
                    var result=[];
                    arr.filter(function(item,index){
                        return item===target&&result.push(index);
                    });
                    return result;
                }
                //lastIndexOf+slice/splice
                function findAllOccurrences_lastIndexOf(arr, target) {
                    var result=[],index=arr.lastIndexOf(target);
                    while(index>-1){
                        result.push(index);
                        // 移除 index 对应的元素
                        arr.splice(index,1);//arr=arr.slice(0,index);
                        index=arr.lastIndexOf(target);
                    }
                    return result;
                }
                //indexOf
                function findAllOccurrences_indexOf(arr, target) {
                    var result=[],index=arr.indexOf(target);
                    while(index>-1){
                        result.push(index);
                        index=arr.indexOf(target,index+1);
                    }
                    return result;
                }
                var a = findAllOccurrences(['a','b','c','d','e','f','a','b','c'],'a')
                a = findAllOccurrences_filter(['a','b','c','d','e','f','a','b','c'],'a')
                a = findAllOccurrences_lastIndexOf(['a','b','c','d','e','f','a','b','c'],'a')
                a = findAllOccurrences_indexOf(['a','b','c','d','e','f','a','b','c'],'a')
                console.log(a)

                // 在Javascript语言中，声明变量使用的都是关键字var，如果不使用var而直接声明变量，则该变量为全局变量。
                function globals() {
                    //只需要在声明myObject时加上var就行了
                    var myObject = {
                    name : 'Jory'
                    };
                
                    return myObject;
                }
                
                // 请修复给定的 js 代码中，函数定义存在的问题
                /*
                function functions(flag) {
                    if (flag) {
                    function getValue() { return 'a'; }
                    } else {
                    function getValue() { return 'b'; }
                    }

                    return getValue();
                }
                这道题是考函数声明与函数表达式的区别，原题的写法，是在两个逻辑分支里面各有一个函数声明，
                但是对于函数声明，解析器会率先读取并且让其在执行任何代码前可用，意思就是别的代码还没运行呢，
                两个getValue声明已经被读取，所以总是执行最新的那个。函数表达式，当解析器执行到它所在的代码行时，
                才会真正被解释执行，所以两个逻辑分支可以分别执行
                
                else中的语句相当于将if中的function重写，因此无论flag为何值，返回的方法始终为重写后的方法。
                将方法赋值给一个变量，方法就不会被重写，因此才能得到正确的结果。
                */
                function functions(flag) {
                    if (flag) {
                        var getValue = function () { return 'a'; }
                    } else {
                        var getValue = function () { return 'b'; }
                    }

                    return getValue();
                }
                // 修改 js 代码中 parseInt 的调用方式，使之通过全部测试用例
                /*
                    输入：'12'   输出：12
                    输入：'12px' 输出：12
                    输入：'0x12' 输出：0
                    function parse2Int(num) {
                        return parseInt(num);
                    }
                    parseInt(string, radix) 当参数 radix 的值为 0，或没有设置该参数时，
                    parseInt() 会根据 string 来判断数字的基数。
                    举例，如果 string 以 "0x" 开头，parseInt() 会把 string 的其余部分解析为十六进制的整数。
                    如果 string 以 0 开头，那么 ECMAScript v3 允许 parseInt() 的一个实现把其后的字符解析
                    为八进制或十六进制的数字。如果 string 以 1 ~ 9 的数字开头，parseInt() 将把它解析为十进制的整数。
                */
                function parse2Int(num) {
                    return parseInt(num,10);
                }
                // 判断 val1 和 val2 是否完全等同
                /*
                function identity(val1, val2) {
                    return val1 === val2
                }
                一般使用双等来判断（==），如果还需要类型相同那么就用三等（===）。
                说一下这两个的区别：
                == equality 等同，=== identity 恒等。
                ==， 两边值类型不同的时候，要先进行类型转换，再比较。 
                ===，不做类型转换，类型不同的一定不等。 
                下面分别说明： 
                先说 ===，这个比较简单。下面的规则用来判断两个值是否===相等： 
                1、如果类型不同，就[不相等] 
                2、如果两个都是数值，并且是同一个值，那么[相等]。
                3、如果两个都是字符串，每个位置的字符都一样，那么[相等]；否则[不相等]。 
                4、如果两个值都是true，或者都是false，那么[相等]。 
                5、如果两个值都引用同一个对象或函数，那么[相等]；否则[不相等]。 
                6、如果两个值都是null，或者都是undefined，那么[相等]。 
                再说 ==，根据以下规则： 
                1、如果两个值类型相同，进行 === 比较。 
                2、如果两个值类型不同，他们可能相等。根据下面规则进行类型转换再比较： 
                a、如果一个是null、一个是undefined，那么[相等]。 
                b、如果一个是字符串，一个是数值，把字符串转换成数值再进行比较。 
                c、如果任一值是 true，把它转换成 1 再比较；如果任一值是 false，把它转换成 0 再比较。 
                d、任何其他组合，都[不相等]。
                
                更加详细的：
                function identity(val1, val2) {
                    if(val1===val2){
                        // +0不等于-0；但是用===的话会返回true；所以要做额外的判断
                        return val1 !== 0 || val2 !== 0 || 1/val1 === 1/val2;
                    }else {
                        //NaN等于NaN 但是NaN === NaN 等于true;所以做额外的判断
                        return val1 !== val1 && val2!== val2;
                    }
                }
                */

                /*
                实现一个打点计时器，要求
                1、从 start 到 end（包含 start 和 end），每隔 100 毫秒 console.log 一个数字，每次数字增幅为 1
                2、返回的对象中需要包含一个 cancel 方法，用于停止定时操作
                3、第一个数需要立即输出

                setInterval() 方法会按照指定周期不停地调用函数，直到 clearInterval() 被调用或窗口被关闭。
                由 setInterval() 返回的 ID 值可用作 clearInterval() 方法的参数。注意第一个数需要立即输出即可。
                function count(start, end) {
                    //立即输出第一个值
                    console.log(start++);
                    var timer = setInterval(function(){
                        if(start <= end){
                            console.log(start++);
                        }else{
                            clearInterval(timer);
                        }
                    },100);
                    //返回一个对象
                    return {
                        cancel : function(){
                            clearInterval(timer);
                        }
                    };
                }
                */

                // 将数组 arr 中的元素作为调用函数 fn 的参数
                /*
                    输入：
                    function (greeting, name, punctuation) {return greeting + ', ' + name + (punctuation || '!');}, ['Hello', 'Ellie', '!']
                    输出：
                    Hello, Ellie!

                    function argsAsArray(fn, arr) {
                        return fn.apply(this,arr)
                    }

                    调用函数可以使用call或者apply这两个方法，区别在于
                    call：需要将传递给函数的参数明确写出来，是多少参数就需要写多少参数；
                    apply：则将传递给函数的参数放入一个数组中，传入参数数组即可。

                    调用函数有3种方式：
                    obj.func();
                    func.call(obj,args);//参数列出
                    func.apply(obj,[m,n......]);//参数数组

                    ES6方法：
                    function argsAsArray(fn, arr) {
                        return fn(...arr)
                    }
                */
                // 将函数 fn 的执行上下文改为 obj 对象
                /*
                    将函数 fn 的执行上下文改为 obj 对象
                    输入：function () {return this.greeting + ', ' + this.name + '!!!';}, {greeting: 'Hello', name: 'Rebecca'}
                    输出：Hello, Rebecca!!!
                    function speak(fn, obj) {
                        return fn.apply(obj,obj)
                    }

                    在JavaScript中，函数是一种对象，其上下文是可以变化的，对应的，函数内的this也是可以变化的，
                    函数可以作为一个对象的方法，也可以同时作为另一个对象的方法，可以通过Function对象中的call
                    或者apply方法来修改函数的上下文，函数中的this指针将被替换为call或者apply的第一个参数。
                    将函数 fn 的执行上下文改为 obj 对象，只需要将obj作为call或者apply的第一个参数传入即可。

                    //三种方案
                    //apply
                    function speak(fn, obj) {
                        return fn.apply(obj);
                    }
                    //call
                    function speak(fn, obj) {
                        return fn.call(obj);
                    }
                    //bind
                    function speak(fn, obj) {
                        return fn.bind(obj)();
                    }
                */


            })();
        </script>
    </head>
    <body>
        <div>
            js
        </div>

    </body>
</html>